import 'package:flutter/material.dart';
import 'package:tuple/tuple.dart';

class TupleExamplePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _TupleExamplePageState();

}

class _TupleExamplePageState extends State<TupleExamplePage> {
  final t2 = Tuple2<int, String>(1, 'a');
  final t3 = Tuple3<int, String, int>(1, 'a', 10);
  final t4 = Tuple4<int, String, int, String>(1, 'a', 10, 'b');
  final t5 = Tuple5<int, String, int, String, int>(1, 'a', 10, 'b', 100);
  final t6 = Tuple6<int, String, int, String, int, String>(1, 'a', 10, 'b', 100, 'c');
  final t7 = Tuple7<int, String, int, String, int, String, int>(1, 'a', 10, 'b', 100, 'c', 1000);

  String value = '';

  expect(var testValue) {
    if(value == '') {
      value = testValue.toString();
    } else {
      value = "$value\n${testValue.toString()}";
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('TupleExamplePage'),
      ),
      body: Center(
        child: Column(
          children: [
            Container(
                height: 150,
                margin: const EdgeInsets.only(bottom: 10),
                child: SingleChildScrollView(child: Text(
                  value,
                  style: const TextStyle(fontSize: 20),
                ))),
            Expanded(
                child: SingleChildScrollView(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      const Text('Tuple2'),
                      _commonButton(context, 'has the correct items', () {
                        value = '';
                        expect(t2.item1);
                        expect(t2.item2);
                        setState(() {});
                      }),
                      _commonButton(context, '\'s fromList', () {
                        value = '';
                        expect(() => Tuple2<int, String>.fromList([]));
                        expect(() => Tuple2<int, String>.fromList([1]));
                        expect(() => Tuple2<int, String>.fromList([1, 'a', 3]));
                        expect(() => Tuple2<int, String>.fromList(['a', 'b']));
                        expect(() => Tuple2<int, String>.fromList([1, 2.0]));
                        setState(() {});
                      }),
                      _commonButton(context, 'returns correct tuple from withItem1 and from withItem2', () {
                        value = '';
                        expect(t2.withItem1(2));
                        expect(t2.withItem2('b'));
                        setState(() {});
                      }),
                      _commonButton(context, '\'s toList', () {
                        value = '';
                        final list = t2.toList();
                        expect(list);
                        expect(() => list.add(1));
                        expect(t2.toList(growable: true)..add('b'));
                        setState(() {});
                      }),
                      _commonButton(context, 'converts to proper string', () {
                        value = '';
                        expect('$t2');
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when first value is different', () {
                        value = '';
                        expect(t2 == t2.withItem1(2));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when second value is different', () {
                        value = '';
                        expect(t2 == t2.withItem2('b'));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when both values are different', () {
                        value = '';
                        expect(t2 == Tuple2<int, String>(2, 'b'));
                        setState(() {});
                      }),
                      _commonButton(context, 'equals itself', () {
                        value = '';
                        expect(t2 == t2);
                        setState(() {});
                      }),
                      _commonButton(context, 'equals another object with same values', () {
                        value = '';
                        expect(t2 == Tuple2<int, String>(1, 'a'));
                        setState(() {});
                      }),
                      _commonButton(context, 'can be used as a map key', () {
                        value = '';
                        final map = <Tuple2<int, String>, int>{};
                        map[t2] = 101;
                        expect(map[Tuple2<int, String>(1, 'a')]);
                        setState(() {});
                      }),
                      const Text('Tuple3'),
                      _commonButton(context, 'has the correct items', () {
                        value = '';
                        expect(t3.item1);
                        expect(t3.item2);
                        expect(t3.item3);
                        setState(() {});
                      }),
                      _commonButton(context, '\'s fromList', () {
                        value = '';
                        expect(() => Tuple3<int, String, int>.fromList([]));
                        expect(() => Tuple3<int, String, int>.fromList([1]));
                        expect(() => Tuple3<int, String, int>.fromList([1, 'a']));
                        expect(() => Tuple3<int, String, int>.fromList([1, 'a', 2, 3]));
                        expect(() => Tuple3<int, String, int>.fromList(['', 'a', 10]));
                        expect(() => Tuple3<int, String, int>.fromList([1, 2, 10]));
                        expect(() => Tuple3<int, String, int>.fromList([1, 'a', 'b']));
                        setState(() {});
                      }),
                      _commonButton(context, 'returns correct tuple from withItem1 and from withItem2 and from withItem3', () {
                        value = '';
                        expect(t3.withItem1(2));
                        expect(t3.withItem2('b'));
                        expect(t3.withItem3(100));
                        setState(() {});
                      }),
                      _commonButton(context, '\'s toList', () {
                        value = '';
                        final list = t3.toList();
                        expect(list);
                        expect(() => list.add(1));
                        expect(t3.toList(growable: true)..add('b'));
                        setState(() {});
                      }),
                      _commonButton(context, 'converts to proper string', () {
                        value = '';
                        expect('$t3');
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when first value is different', () {
                        value = '';
                        expect(t3 == t3.withItem1(2));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when second value is different', () {
                        value = '';
                        expect(t3 == t3.withItem2('b'));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when third value is different', () {
                        value = '';
                        expect(t3 == t3.withItem3(100));
                        setState(() {});
                      }),
                      _commonButton(context, 'equals itself', () {
                        value = '';
                        expect(t3 == t3);
                        setState(() {});
                      }),
                      _commonButton(context, 'equals another object with same values', () {
                        value = '';
                        expect(t3 == Tuple3<int, String, int>(1, 'a', 10));
                        setState(() {});
                      }),
                      _commonButton(context, 'can be used as a map key', () {
                        value = '';
                        final map = <Tuple3<int, String, int>, int>{};
                        map[t3] = 101;
                        expect(map[Tuple3<int, String, int>(1, 'a', 10)]);
                        setState(() {});
                      }),
                      const Text('Tuple4'),
                      _commonButton(context, 'has the correct items', () {
                        value = '';
                        expect(t4.item1);
                        expect(t4.item2);
                        expect(t4.item3);
                        expect(t4.item4);
                        setState(() {});
                      }),
                      _commonButton(context, '\'s fromList', () {
                        value = '';
                        expect(() => Tuple4<int, String, int, String>.fromList([]));
                        expect(() => Tuple4<int, String, int, String>.fromList([1]));
                        expect(() => Tuple4<int, String, int, String>.fromList([1, 'a']));
                        expect(() => Tuple4<int, String, int, String>.fromList([1, 'a', 2]));
                        expect(() => Tuple4<int, String, int, String>.fromList([1, 'a', 2, 'b', 3]));
                        expect(() => Tuple4<int, String, int, String>.fromList(['', 'a', 2, 'b']));
                        expect(() => Tuple4<int, String, int, String>.fromList([1, 2, 3, 'b']));
                        expect(() => Tuple4<int, String, int, String>.fromList([1, 'a', 'b', 2]));
                        expect(() => Tuple4<int, String, int, String>.fromList([1, 'a', 2, 3]));
                        setState(() {});
                      }),
                      _commonButton(context, 'returns correct tuple from withItem1 and from withItem2 and from withItem3 and from withItem4', () {
                        value = '';
                        expect(t4.withItem1(2));
                        expect(t4.withItem2('b'));
                        expect(t4.withItem3(100));
                        expect(t4.withItem4('c'));
                        setState(() {});
                      }),
                      _commonButton(context, '\'s toList', () {
                        value = '';
                        final list = t4.toList();
                        expect(list);
                        expect(() => list.add(1));
                        expect(t4.toList(growable: true)..add('c'));
                        setState(() {});
                      }),
                      _commonButton(context, 'converts to proper string', () {
                        value = '';
                        expect('$t4');
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when first value is different', () {
                        value = '';
                        expect(t4 == t4.withItem1(2));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when second value is different', () {
                        value = '';
                        expect(t4 == t4.withItem2('b'));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when third value is different', () {
                        value = '';
                        expect(t4 == t4.withItem3(100));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when fourth value is different', () {
                        value = '';
                        expect(t4 == t4.withItem4('c'));
                        setState(() {});
                      }),
                      _commonButton(context, 'equals itself', () {
                        value = '';
                        expect(t4 == t4);
                        setState(() {});
                      }),
                      _commonButton(context, 'equals another object with same values', () {
                        value = '';
                        expect(t4 == Tuple4<int, String, int, String>(1, 'a', 10, 'b'));
                        setState(() {});
                      }),
                      _commonButton(context, 'can be used as a map key', () {
                        value = '';
                        final map = <Tuple4<int, String, int, String>, int>{};
                        map[t4] = 101;
                        expect(map[Tuple4<int, String, int, String>(1, 'a', 10, 'b')]);
                        setState(() {});
                      }),
                      const Text('Tuple5'),
                      _commonButton(context, 'has the correct items', () {
                        value = '';
                        expect(t5.item1);
                        expect(t5.item2);
                        expect(t5.item3);
                        expect(t5.item4);
                        expect(t5.item5);
                        setState(() {});
                      }),
                      _commonButton(context, '\'s fromList', () {
                        value = '';
                        expect(() => Tuple5<int, String, int, String, int>.fromList([]));
                        expect(() => Tuple5<int, String, int, String, int>.fromList([1]));
                        expect(() => Tuple5<int, String, int, String, int>.fromList([1, 'a']));
                        expect(() => Tuple5<int, String, int, String, int>.fromList([1, 'a', 2]));
                        expect(() => Tuple5<int, String, int, String, int>.fromList([1, 'a', 2, 'b']));
                        expect(() => Tuple5<int, String, int, String, int>.fromList([1, 'a', 2, 'b', 3, 'c']));
                        expect(() => Tuple5<int, String, int, String, int>.fromList(['z', 'a', 2, 'b', 3]));
                        expect(() => Tuple5<int, String, int, String, int>.fromList([1, 0, 2, 'b', 3]));
                        expect(() => Tuple5<int, String, int, String, int>.fromList([1, 'a', 'z', 'b', 3]));
                        expect(() => Tuple5<int, String, int, String, int>.fromList([1, 'a', 2, 0, 3]));
                        expect(() => Tuple5<int, String, int, String, int>.fromList([1, 'a', 2, 'b', 'z']));
                        setState(() {});
                      }),
                      _commonButton(context, 'returns correct tuple from withItem1 and from withItem2 and from withItem3 and from withItem4 and from withItem5', () {
                        value = '';
                        expect(t5.withItem1(2));
                        expect(t5.withItem2('b'));
                        expect(t5.withItem3(100));
                        expect(t5.withItem4('c'));
                        expect(t5.withItem5(4));
                        setState(() {});
                      }),
                      _commonButton(context, '\'s toList', () {
                        value = '';
                        final list = t5.toList();
                        expect(list);
                        expect(() => list.add(1));
                        expect(t5.toList(growable: true)..add('c'));
                        setState(() {});
                      }),
                      _commonButton(context, 'converts to proper string', () {
                        value = '';
                        expect('$t5');
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when first value is different', () {
                        value = '';
                        expect(t5 == t5.withItem1(2));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when second value is different', () {
                        value = '';
                        expect(t5 == t5.withItem2('b'));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when third value is different', () {
                        value = '';
                        expect(t5 == t5.withItem3(100));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when fourth value is different', () {
                        value = '';
                        expect(t5 == t5.withItem4('c'));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when fifth value is different', () {
                        value = '';
                        expect(t5 == t5.withItem5(0));
                        setState(() {});
                      }),
                      _commonButton(context, 'equals itself', () {
                        value = '';
                        expect(t5 == t5);
                        setState(() {});
                      }),
                      _commonButton(context, 'equals another object with same values', () {
                        value = '';
                        expect(t5 == Tuple5<int, String, int, String, int>(1, 'a', 10, 'b', 100));
                        setState(() {});
                      }),
                      _commonButton(context, 'can be used as a map key', () {
                        value = '';
                        final map = <Tuple5<int, String, int, String, int>, int>{};
                        map[t5] = 101;
                        expect(map[Tuple5<int, String, int, String, int>(1, 'a', 10, 'b', 100)]);
                        setState(() {});
                      }),
                      const Text('Tuple6'),
                      _commonButton(context, 'has the correct items', () {
                        value = '';
                        expect(t6.item1);
                        expect(t6.item2);
                        expect(t6.item3);
                        expect(t6.item4);
                        expect(t6.item5);
                        expect(t6.item6);
                        setState(() {});
                      }),
                      _commonButton(context, '\'s fromList', () {
                        value = '';
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([]));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1]));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1, 'a']));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1, 'a', 2]));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1, 'a', 2, 'b']));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1, 'a', 2, 'b', 3]));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1, 'a', 2, 'b', 3, 'c', 4]));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList(['z', 'a', 2, 'b', 3, 'c']));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1, 0, 2, 'b', 3, 'c']));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1, 'a', 'z', 'b', 3, 'c']));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1, 'a', 2, 0, 3, 'c']));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1, 'a', 2, 'b', 'z', 'c']));
                        expect(() => Tuple6<int, String, int, String, int, String>.fromList([1, 'a', 2, 'b', 3, 4]));
                        setState(() {});
                      }),
                      _commonButton(context, 'returns correct tuple from withItem1 and from withItem2 and from withItem3 '
                          'and from withItem4 and from withItem5 and from withItem6', () {
                        value = '';
                        expect(t6.withItem1(2));
                        expect(t6.withItem2('b'));
                        expect(t6.withItem3(100));
                        expect(t6.withItem4('c'));
                        expect(t6.withItem5(4));
                        expect(t6.withItem6('z'));
                        setState(() {});
                      }),
                      _commonButton(context, '\'s toList', () {
                        value = '';
                        final list = t6.toList();
                        expect(list);
                        expect(() => list.add(1));
                        expect(t6.toList(growable: true)..add(1));
                        setState(() {});
                      }),
                      _commonButton(context, 'converts to proper string', () {
                        value = '';
                        expect('$t6');
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when first value is different', () {
                        value = '';
                        expect(t6 == t6.withItem1(2));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when second value is different', () {
                        value = '';
                        expect(t6 == t6.withItem2('b'));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when third value is different', () {
                        value = '';
                        expect(t6 == t6.withItem3(100));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when fourth value is different', () {
                        value = '';
                        expect(t6 == t6.withItem4('c'));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when fifth value is different', () {
                        value = '';
                        expect(t6 == t6.withItem5(0));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when sixth value is different', () {
                        value = '';
                        expect(t6 == t6.withItem6('z'));
                        setState(() {});
                      }),
                      _commonButton(context, 'equals itself', () {
                        value = '';
                        expect(t6 == t6);
                        setState(() {});
                      }),
                      _commonButton(context, 'equals another object with same values', () {
                        value = '';
                        expect(t6 == Tuple6<int, String, int, String, int, String>(1, 'a', 10, 'b', 100, 'c'));
                        setState(() {});
                      }),
                      _commonButton(context, 'can be used as a map key', () {
                        value = '';
                        final map = <Tuple6<int, String, int, String, int, String>, int>{};
                        map[t6] = 101;
                        expect(map[Tuple6<int, String, int, String, int, String>(1, 'a', 10, 'b', 100, 'c')]);
                        setState(() {});
                      }),
                      const Text('Tuple7'),
                      _commonButton(context, 'has the correct items', () {
                        value = '';
                        expect(t7.item1);
                        expect(t7.item2);
                        expect(t7.item3);
                        expect(t7.item4);
                        expect(t7.item5);
                        expect(t7.item6);
                        expect(t7.item7);
                        setState(() {});
                      }),
                      _commonButton(context, '\'s fromList', () {
                        value = '';
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([]));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1]));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a']));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a', 2]));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a', 2, 'b']));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a', 2, 'b', 3]));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a', 2, 'b', 3, 'c']));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a', 2, 'b', 3, 'c', 4, 'd']));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList(['z', 'a', 2, 'b', 3, 'c', 4]));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 0, 2, 'b', 3, 'c', 4]));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a', 'z', 'b', 3, 'c', 4]));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a', 2, 0, 3, 'c', 4]));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a', 2, 'b', 'z', 'c', 4]));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a', 2, 'b', 3, 4, 5]));
                        expect(() => Tuple7<int, String, int, String, int, String, int>.fromList([1, 'a', 2, 'b', 3, 'c', 'd']));
                        setState(() {});
                      }),
                      _commonButton(context, 'returns correct tuple from withItem1 and from withItem2 and from withItem3 '
                          'and from withItem4 and from withItem5 and from withItem6 and from withItem7', () {
                        value = '';
                        expect(t7.withItem1(2));
                        expect(t7.withItem2('b'));
                        expect(t7.withItem3(100));
                        expect(t7.withItem4('c'));
                        expect(t7.withItem5(4));
                        expect(t7.withItem6('z'));
                        expect(t7.withItem7(0));
                        setState(() {});
                      }),
                      _commonButton(context, '\'s toList', () {
                        value = '';
                        final list = t7.toList();
                        expect(list);
                        expect(() => list.add(1));
                        expect(t7.toList(growable: true)..add(1));
                        setState(() {});
                      }),
                      _commonButton(context, 'converts to proper string', () {
                        value = '';
                        expect('$t7');
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when first value is different', () {
                        value = '';
                        expect(t7 == t7.withItem1(2));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when second value is different', () {
                        value = '';
                        expect(t7 == t7.withItem2('b'));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when third value is different', () {
                        value = '';
                        expect(t7 == t7.withItem3(100));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when fourth value is different', () {
                        value = '';
                        expect(t7 == t7.withItem4('c'));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when fifth value is different', () {
                        value = '';
                        expect(t7 == t7.withItem5(0));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when sixth value is different', () {
                        value = '';
                        expect(t7 == t7.withItem6('z'));
                        setState(() {});
                      }),
                      _commonButton(context, 'does not equal when seventh value is different', () {
                        value = '';
                        expect(t7 == t7.withItem7(0));
                        setState(() {});
                      }),
                      _commonButton(context, 'equals itself', () {
                        value = '';
                        expect(t7 == t7);
                        setState(() {});
                      }),
                      _commonButton(context, 'equals another object with same values', () {
                        value = '';
                        expect(t7 == Tuple7<int, String, int, String, int, String, int>(1, 'a', 10, 'b', 100, 'c', 1000));
                        setState(() {});
                      }),
                      _commonButton(context, 'can be used as a map key', () {
                        value = '';
                        final map = <Tuple7<int, String, int, String, int, String, int>, int>{};
                        map[t7] = 101;
                        expect(map[Tuple7<int, String, int, String, int, String, int>(1, 'a', 10, 'b', 100, 'c', 1000)]);
                        setState(() {});
                      }),
                    ],
                  ),
                )
            )
          ],
        ),
      ),
    );
  }
}

Widget _commonButton(BuildContext context, String title, Function() onTap) {
  return Container(
      width: MediaQuery.of(context).size.width * 0.7,
      margin: const EdgeInsets.only(bottom: 10),
      child: MaterialButton(
        onPressed: onTap,
        color: Colors.blue,
        child: Text(title),
      )
  );
}